#include <PA9.h>
#include "sprite.h"
#include "palette.h"
#include "graphic.h"

namespace game{
   
    void Sprite::initialize(bool screen, Palette* objPalette, Graphic* objGraphic){
        Sprite::screen = screen;
        Sprite::palette = objPalette;
        Sprite::graphic = objGraphic;
        Sprite::loaded = false;
        Sprite::frame = 0;
        Sprite::maxFrame = 1;
        Sprite::spriteid = -1;
        Sprite::rotset = 0;
    }
    
        
    void Sprite::dualScreenSpace(s16 space){
        PA_SetScreenSpace(space);
    }
    
    Sprite::Sprite(bool screen, Palette* objPalette, Graphic* objGraphic){
        initialize(screen, objPalette, objGraphic);
    }
    
    Sprite::Sprite(bool screen, Palette* objPalette, Graphic* objGraphic, s16 maxFrame){
        initialize(screen, objPalette, objGraphic);
        Sprite::maxFrame = maxFrame;
    }
    
    void Sprite::load(u8 id, s16 x, s16 y){
        spriteid = id;
        
        palette->load();
        graphic->load();
        
        PA_CreateSpriteFromGfx(screen,
                                spriteid,
                                graphic->getid(),
                                graphic->getshape(),
                                graphic->getsize(),
                                graphic->getcolormode(),
                                palette->getid(),
                                x,
                                y);
        loaded = true;
        dual = false;
    }
    
    void Sprite::loaddual(u8 id, s16 x, s16 y){
        spriteid = id;
        
        palette->loaddual();
        graphic->loaddual();
        
        PA_DualCreateSpriteFromGfx(spriteid,
                                (u16*)graphic->getdualid(),
                                graphic->getshape(),
                                graphic->getsize(),
                                graphic->getcolormode(),
                                palette->getdualid(),
                                x,
                                y);
        loaded = true;
        dual = true;
    }
    
    void Sprite::remove(){
        if(loaded){
            if (dual){
                PA_DualDeleteSprite(spriteid);
            }
            else{
                PA_DeleteSprite(screen, spriteid);
            }
            spriteid = -1;
            loaded = false;
        }
    }
    
    void Sprite::reload(){
        if(loaded){
            u8 id = getid();
            s16 x = getx();
            s16 y = gety();
            
            remove();
            if (dual)
            {
               loaddual(id, x, y);
            }
            else
            {
               load(id, x, y);    
            }
        }
    }

    Sprite* Sprite::duplicate(){
        return duplicate(screen);
    }
    
    Sprite* Sprite::duplicate(bool screen){
        return new Sprite(screen, palette, graphic);
    }
    
    Sprite::~Sprite(){
        remove();
    }
    
    u8 Sprite::getid(){
        return spriteid;
    }
    
    bool Sprite::isloaded(){
        return loaded;
    }
    
    Graphic* Sprite::getgraphic(){
        return graphic;
    }
    
    void Sprite::setgraphic(Graphic* objGraphic){
        graphic = objGraphic;
        if(loaded)
        {
            if (dual)
            {
                PA_DualSetSpriteGfx(spriteid, (u16*)graphic->getdualid());
            }
            else
            {
                PA_SetSpriteGfx(screen, spriteid, graphic->getid());
            }
        }
    }
    
    Palette* Sprite::getpalette(){
        return palette;
    }
    
    void Sprite::setpalette(Palette* objPalette){
        palette = objPalette;
        if(loaded)
        {
            if (dual)
            {
                PA_DualSetSpritePal(spriteid, palette->getdualid());
            }
            else
            {
                PA_SetSpritePal(screen, spriteid, palette->getid());
            }
        }
    }
    
    bool Sprite::getvflip(){
        if(loaded)
        {
            if (dual)
            {
                return PA_GetSpriteVflip(screen, spriteid);
            }
            else
            {
                return PA_GetSpriteVflip(screen, spriteid);
            }
        }    
        return false;
    }
    
    void Sprite::setvflip(bool vflip){
        if(loaded)
        {
            if (dual)
            {
                PA_DualSetSpriteVflip(spriteid, vflip);
            }
            else
            {
                PA_SetSpriteVflip(screen, spriteid, vflip);
            }
        }    
    }
    
    void Sprite::flipv(){
        if(loaded)
            setvflip(!getvflip());        
    }
    
    bool Sprite::gethflip(){
        if(loaded)
        {
            if (dual)
            {
                return PA_GetSpriteHflip(screen, spriteid);
            }
            else
            {
                return PA_GetSpriteHflip(screen, spriteid);
            }
        }    
        return false;
    }
    
    void Sprite::sethflip(bool hflip){
        if(loaded)
            {
            if (dual)
            {
                PA_DualSetSpriteHflip(spriteid, hflip);
            }
            else
            {
                PA_SetSpriteHflip(screen, spriteid, hflip);
            }
        }
    }
    
    void Sprite::fliph(){
        if(loaded)
            sethflip(!gethflip());
    }

    void Sprite::enablerot(u8 rotset){
        if(loaded){
            this->rotset = rotset;
            if (dual)
            {
                PA_DualSetSpriteRotEnable(spriteid, rotset);
            }
            else
            {
                PA_SetSpriteRotEnable(screen, spriteid, rotset);     
            }    
        }
    }
    
    void Sprite::disablerot(){
        if(loaded)
        {
            if (dual)
            {
                PA_DualSetSpriteRotDisable(spriteid);
            }
            else
            {
                PA_SetSpriteRotDisable(screen, spriteid);
            }    
        }    
    }
    
    void Sprite::setzoomangle(s16 angle, u16 zoomx, u16 zoomy){
        if(loaded)
        {
            if (dual)
            {
                PA_DualSetRotset(rotset, angle, zoomx, zoomy);
            }
            else
            {
                PA_SetRotset(screen, rotset, angle, zoomx, zoomy);
            }
        }    
    }
    
    void Sprite::setzoom(u16 zoomx, u16 zoomy){
        if(loaded)
        {
            if (dual)
            {
                PA_DualSetRotsetNoAngle(rotset, zoomx, zoomy);
            }
            else
            {
                PA_SetRotsetNoAngle(screen, rotset, zoomx, zoomy);
            }    
        }    
    }
    
    void Sprite::setangle(s16 angle){
        if(loaded)
        {
            if (dual)
            { 
                PA_DualSetRotsetNoZoom(rotset, angle);
            }
            else
            {
                PA_SetRotsetNoZoom(screen, rotset, angle);
            }    
        }    
    }
    
    void Sprite::setdoublesize(bool dblsize){
        if(loaded)
            PA_SetSpriteDblsize(screen, spriteid, dblsize);
    }

    bool Sprite::getdoublesize(){
        if(loaded)
            return PA_GetSpriteDblsize(screen, spriteid);
        return false;
    }
    
    void Sprite::setxy(s16 x, s16 y){
        if(loaded){
            if(dual)
                PA_DualSetSpriteXY(spriteid, x, y);
            else
                PA_SetSpriteXY(screen, spriteid, x, y);
        }
    }
    
    s16 Sprite::getx(){
        if(loaded){
            return PA_GetSpriteX(screen, spriteid);
        }
        return 0;
    }
    
    void Sprite::setx(s16 x){
        if(loaded){
            if(dual)
                PA_DualSetSpriteX(spriteid, x);
            else
                PA_SetSpriteX(screen, spriteid, x);
        }
    }

    s16 Sprite::gety(){
        if(loaded)
            return PA_GetSpriteY(screen, spriteid);
        return 0;
    }
    
    void Sprite::sety(s16 y){
        if(loaded){
            if(dual)
                PA_DualSetSpriteY(spriteid, y);
            else
                PA_SetSpriteY(screen, spriteid, y);
        }
    }
    
    u8 Sprite::getpriority(){
        if(loaded)
            return PA_GetSpritePrio(screen, spriteid);
        return 0;
    }
    
    void Sprite::setpriority(u8 p){
        if(loaded)
            PA_SetSpritePrio(screen, spriteid, p);
    }

    s16 Sprite::getframe(){
        if(loaded)
            return frame;
        return 0;
    }

    void Sprite::setframe(s16 frame){
        if(loaded){
            if(frame >= maxFrame)
                this->frame = frame % maxFrame;
            else
                this->frame = frame;
            PA_SetSpriteAnim(screen, spriteid, this->frame);
        }
    }
    
    bool Sprite::isTouched(){
        if(loaded){
            if(screen) return false;
            return PA_SpriteTouched(spriteid);
        }
        return false;
    }
    
    bool Sprite::isTouched(u8 w, u8 h){
        if(loaded){
            if(screen) return false;
            return PA_SpriteTouchedEx(spriteid, w, h);
        }
        return false;
    }
}
